home *** CD-ROM | disk | FTP | other *** search
/ APDL Other Worlds / APDL Other Worlds Collection.iso / SF3000 / Extras / !SFtoSpr / c / SFgfxconv < prev    next >
Encoding:
Text File  |  2003-11-06  |  20.3 KB  |  580 lines

  1. /*
  2.  *  SFtoSpr - Star Fighter 3000 graphics converter
  3.  *  Graphics conversion routines
  4.  *  Copyright (C) 2000  Chris Bazley
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public Licence as published by
  8.  *  the Free Software Foundation; either version 2 of the Licence, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public Licence for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public Licence
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  */
  20.  
  21. /* ANSI headers */
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <stdio.h>
  25. #include <limits.h>
  26. #include <stdbool.h>
  27.  
  28. /* RISC OS headers */
  29. #include "kernel.h"
  30. #include "swis.h"
  31. #include "wimplib.h"
  32.  
  33. /* My library files */
  34. #include "err.h"
  35. #include "msgtrans.h"
  36. #include "SFformats.h"
  37. #include "SprFormats.h"
  38. #include "hourglass.h"
  39. #include "Macros.h"
  40. #include "flex.h"
  41. #include "NoBudge.h"
  42.  
  43. /* Local headers */
  44. #include "Main.h"
  45. #include "Utils.h"
  46. #include "SFgfxconv.h"
  47.  
  48. /* Sprite output is 8bpp, 45x45 dpi */
  49. /* Old-style mode number: */
  50. #define OUTPUT_TYPE_MODE 13
  51. /* New-style sprite type specifier: */
  52. #define OUTPUT_TYPE_NEW (1 | (45<<1) | (45<<14) | (4<<27))
  53.  
  54. /* ----------------------------------------------------------------------- */
  55. /*                       Function prototypes                               */
  56.  
  57. static int check_spr_type(int type);
  58.  
  59. /* ----------------------------------------------------------------------- */
  60. /*                         Public functions                                */
  61.  
  62. int spritehdr_validtile(spriteheader *sph, const char *spritename)
  63. {
  64.   /* check sprite header (ignore dpi, mask, palette) */
  65.   int tilenum;
  66.   if((sscanf(spritename, "tile_%d", &tilenum) == 1
  67.       /* provide for old style sprite naming */
  68.    || sscanf(spritename, "tile_%d", &tilenum) == 1)
  69.   && sph->width == (SF_MAPTILE_WIDTH/4)-1
  70.   && sph->height == SF_MAPTILE_HEIGHT-1
  71.   && sph->left_bit == 0
  72.   && sph->right_bit == 31
  73.   && check_spr_type(sph->type)
  74.   && tilenum >= 0
  75.   && tilenum <= 254)
  76.     return tilenum;
  77.   else
  78.     return -1;
  79. }
  80.  
  81. /* ----------------------------------------------------------------------- */
  82.  
  83. int spritehdr_validpla(spriteheader *sph, const char *spritename)
  84. {
  85.   /* check sprite header (ignore dpi, mask, palette) */
  86.   int planetnum;
  87.   if(sscanf(spritename, "planet_%d", &planetnum) == 1
  88.   && sph->width == (SF_PLANET_WIDTH/4)-1
  89.   && sph->height == SF_PLANET_HEIGHT-1
  90.   && sph->left_bit == 0
  91.   && sph->right_bit == 31
  92.   && check_spr_type(sph->type)
  93.   && planetnum >= 0
  94.   && planetnum <= 1)
  95.     return planetnum;
  96.   else
  97.     return -1;
  98. }
  99.  
  100. /* ----------------------------------------------------------------------- */
  101.  
  102. int get_max_tile_num(spriteareaheader **spritearea)
  103. {
  104.   /* Pre-scan file to find out highest number from all valid tile sprites */
  105.   int max_tilenum;
  106.   spriteheader *input_sprite;
  107.  
  108.   /* we need to multiply by 100 for percentage calculation */
  109.   if(((*spritearea)->sprite_count-1) > (INT_MAX/100))
  110.     M_RETV("TooManySp", -1) /* failure */
  111.  
  112.   max_tilenum = -1; /* could be no valid tile numbers */
  113.   input_sprite = (spriteheader *)((int)(*spritearea) + (*spritearea)->first);
  114.  
  115.   hourglass_on();
  116.   for(int sprite = 0; sprite < (*spritearea)->sprite_count; sprite++) {
  117.     hourglass_percentage((sprite * 100) / (*spritearea)->sprite_count);
  118.  
  119.     /* Check source sprite header */
  120.     char spritename[13];
  121.     strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
  122.     int tilenum = spritehdr_validtile(input_sprite, spritename);
  123.     if(tilenum > max_tilenum)
  124.       max_tilenum = tilenum;
  125.  
  126.     /* Calculate address of next sprite */
  127.     input_sprite = (spriteheader *)((int)input_sprite+input_sprite->size);
  128.   } /* next sprite */
  129.   hourglass_off();
  130.  
  131.   return max_tilenum;
  132. }
  133.  
  134. /* ----------------------------------------------------------------------- */
  135.  
  136. int get_max_planet_num(spriteareaheader **spritearea)
  137. {
  138.   /* Pre-scan file to find out highest number from all valid planet sprites */
  139.   int max_planetnum;
  140.   spriteheader *input_sprite;
  141.  
  142.   /* we need to multiply by 100 for percentage calculation */
  143.   if(((*spritearea)->sprite_count-1) > (INT_MAX/100))
  144.     M_RETV("TooManySp", -1) /* failure */
  145.  
  146.   max_planetnum = -1; /* could be no valid planet numbers */
  147.   input_sprite = (spriteheader *)((int)(*spritearea) + (*spritearea)->first);
  148.  
  149.   hourglass_on();
  150.   for(int sprite = 0; sprite < (*spritearea)->sprite_count; sprite++) {
  151.     hourglass_percentage((sprite * 100) / (*spritearea)->sprite_count);
  152.  
  153.     /* Check source sprite header */
  154.     char spritename[13];
  155.     strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
  156.     int planetnum = spritehdr_validpla(input_sprite, spritename);
  157.     if(planetnum > max_planetnum)
  158.       max_planetnum = planetnum;
  159.  
  160.     /* Calculate address of next sprite */
  161.     input_sprite = (spriteheader *)((int)input_sprite+input_sprite->size);
  162.   } /* next sprite */
  163.   hourglass_off();
  164.  
  165.   return max_planetnum;
  166. }
  167.  
  168.  
  169. /* ----------------------------------------------------------------------- */
  170.  
  171. bool sprites_to_tiles(spriteareaheader **spritearea, SF_MapTilesSetHdr **ret_tileset, bool abandon_on_dud)
  172. {
  173.   /*
  174.   rewritten 19/07/2000 to cope with out-of-order and inappropriate sprites
  175.   rewritten 20/07/2000 to cope with sprites wanting to be bigger tile numbers than the number of sprites in the file
  176.   24.04.01 - eliminated hugely nested error handlers
  177.            - header to write is now a parameter
  178.            - no longer returns an error pointer
  179.   10.05.01 returns code indicating success
  180.            new param 'abandon_on_dud' controls behaviour with dud sprites
  181.   05.06.01 removed (excessive?) memory checking
  182.   11.06.01 queries dud sprites during prescan, blanks free header word, can create empty tiles files
  183.   16.09.01 No longer writes header info (not available until read from window)
  184.            areasize eliminated as a parameter - not needed if no checks
  185.   02.11.01 Copes properly with funny sized header on input sprite area
  186.            Made parameters strongly typed
  187.            now returns an error block rather than 0 for fail
  188.   16.12.01 input and output blocks are both flexlib.
  189.   05.05.02 static pointers to flex blocks
  190.            more scopes to help register allocation
  191.   20.11.02 eliminated floats from hourglass percentage calculation
  192.   05.09.03 fixed memory leak of ret_tileset on error
  193.   */
  194.  
  195.   SF_MapTilesSetHdr *ret_tileset_ptr;
  196.   int max_tilenum;
  197.   /* pointers to write new tile and start of source sprite */
  198.  
  199.   max_tilenum = get_max_tile_num(spritearea);
  200.   if(max_tilenum == -1)
  201.     return false; /* failure */
  202.  
  203.   /* Allocate memory for tile area */
  204.   if(!flex_alloc((flex_ptr)ret_tileset, sizeof(SF_MapTilesSetHdr) + (sizeof(SF_MapTile)*(max_tilenum+1))))
  205.     MG_RETV("NoMem", false) /* failure */
  206.  
  207.   nobudge_register(1024);
  208.   ret_tileset_ptr = *ret_tileset;
  209.  
  210.   /* Initialise tile area */
  211.   memset(ret_tileset_ptr, 0, flex_size((flex_ptr)ret_tileset));
  212.   ret_tileset_ptr->lasttile_num = max_tilenum;
  213.  
  214.   /* Scan sprite area */
  215.   hourglass_on();
  216.   {
  217.     spriteareaheader *spritearea_ptr = *spritearea;
  218.     spriteheader *input_sprite = (spriteheader *)((int)spritearea_ptr + spritearea_ptr->first);
  219.  
  220.     for(int sprite = 0; sprite < spritearea_ptr->sprite_count; sprite++) {
  221.       hourglass_percentage((sprite * 100) / spritearea_ptr->sprite_count);
  222.  
  223.       /* Check source sprite header */
  224.       char spritename[13];
  225.       strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
  226.       int tilenum = spritehdr_validtile(input_sprite, spritename);
  227.       if(tilenum >= 0) {
  228.         char *tile_data_end, *sprite_data_start;
  229.  
  230.         /* Calculate address of end of tile bitmap */
  231.         tile_data_end = (char *)((int)ret_tileset_ptr + sizeof(SF_MapTilesSetHdr) + (tilenum * sizeof(SF_MapTile)) + sizeof(SF_MapTile));
  232.  
  233.         /* calculate address of start of sprite bitmap */
  234.         sprite_data_start = (char *)((int)input_sprite + input_sprite->image);
  235.  
  236.         /* copy across raw bitmap */
  237.         for(int row = 0; row < SF_MAPTILE_HEIGHT; row++) {
  238.           /* notice that tile is reversed up/down during copying */
  239.           /* eg row 0-row 3,row 1-row 2,row 2-row 1, row 3-row 0 */
  240.           memcpy(
  241.             (char *)(tile_data_end - ((row+1)*SF_MAPTILE_WIDTH)),
  242.             (char *)(sprite_data_start + (row*SF_MAPTILE_WIDTH)),
  243.             SF_MAPTILE_WIDTH
  244.           );
  245.         } /* next row of tile */
  246.       }
  247.       else {
  248.         /* Invalid sprite header! */
  249.         nobudge_deregister();
  250.         hourglass_off();
  251.         
  252.         if(abandon_on_dud) {
  253.           /* Abandon rest of file with error */
  254.           err_report(255, msgs_lookup_sub1("BadSprite", spritename));
  255.           flex_free((flex_ptr)ret_tileset);
  256.           return false; /* failure */
  257.         }
  258.         if(!dialogue_confirm(msgs_lookup_sub1("BadSpriteCont", spritename))) {
  259.           flex_free((flex_ptr)ret_tileset);
  260.           return false; /* User wants to abandon rest of file */
  261.         }
  262.         else {
  263.           /* User wants to skip sprite and continue */
  264.           hourglass_on();
  265.           nobudge_register(1024);
  266.         }
  267.       }
  268.  
  269.       /* Calculate address of next sprite */
  270.       input_sprite = (spriteheader *)((int)input_sprite + input_sprite->size);
  271.  
  272.     } /* loop back (next sprite) */
  273.   }
  274.   hourglass_off();
  275.  
  276.   nobudge_deregister();
  277.   return true; /* success */
  278. }
  279.  
  280. /* ----------------------------------------------------------------------- */
  281.  
  282. bool tiles_to_sprites(SF_MapTilesSetHdr **tileset, spriteareaheader **ret_sprarea) {
  283.   /* finished 29/03/00
  284.      re-written to flip tile up/down 10/07/2000
  285.      Checks validity of Sprite area 19/07/2000
  286.      10.05.01 returns code indicating success
  287.      05.06.01 removed (excessive?) memory checking
  288.      16.09.01 areasize eliminated as a parameter - not needed if no checks
  289.      05.10.01 copied from SFtoSpr to SFeditor
  290.               made parameters strongly typed and eliminated *outsize
  291.               now returns an error block rather than 0 for fail
  292.      16.12.01 input and output blocks are both flexlib.
  293.      05.05.02 static pointers to flex blocks
  294.               more scopes to help register allocation
  295.      20.11.02 eliminated floats from hourglass percentage calculation
  296.    */
  297.   int numtiles;
  298.   spriteareaheader *ret_sprarea_ptr;
  299.  
  300.   /* read tile area details */
  301.   numtiles = (*tileset)->lasttile_num + 1;
  302.   if (numtiles < 0 || numtiles > 254)
  303.     M_RETV("BadNumGFX", false)
  304.  
  305.   /* Allocate memory for sprite area */
  306.   if(!flex_alloc((flex_ptr)ret_sprarea, sizeof(spriteareaheader) + ((sizeof(spriteheader)+sizeof(SF_MapTile))*numtiles)))
  307.     MG_RETV("NoMem", false)
  308.  
  309.   nobudge_register(1024);
  310.   ret_sprarea_ptr = *ret_sprarea;
  311.  
  312.   /* initialise sprite area header */
  313.   {
  314.     int size = flex_size((flex_ptr)ret_sprarea);
  315.     ret_sprarea_ptr->size = size;
  316.     ret_sprarea_ptr->sprite_count = numtiles;
  317.     ret_sprarea_ptr->first = sizeof(spriteareaheader);
  318.     ret_sprarea_ptr->used = size;
  319.   }
  320.  
  321.   hourglass_on();
  322.   {
  323.     SF_MapTilesSetHdr *tileset_ptr = *tileset;
  324.     for(int tile = 0; tile < numtiles; tile++) {
  325.       spriteheader *sph;
  326.       char *tile_data_end, *sprite_data_start;
  327.  
  328.       hourglass_percentage((tile * 100) / numtiles);
  329.  
  330.       /* initialise header of new sprite */
  331.       sph = (spriteheader *)( (int)ret_sprarea_ptr + sizeof(spriteareaheader) + (tile * (sizeof(spriteheader) + sizeof(SF_MapTile)) ) ); /* start of sprite */
  332.       sph->size = sizeof(spriteheader) + sizeof(SF_MapTile);
  333.       memset(sph->name, 0, sizeof(sph->name));
  334.       sprintf(sph->name, "tile_%d", tile);
  335.       sph->width = (SF_MAPTILE_WIDTH / 4) - 1;
  336.       sph->height = SF_MAPTILE_HEIGHT - 1;
  337.       sph->left_bit = 0;
  338.       sph->right_bit = 31;
  339.       sph->image = sizeof(spriteheader);
  340.       sph->mask = sizeof(spriteheader);
  341.       if(output_new_format)
  342.         sph->type = OUTPUT_TYPE_NEW; /* New-style sprite type */
  343.       else
  344.         sph->type = OUTPUT_TYPE_MODE; /* old-style mode number */
  345.  
  346.       /* calculate address of end of tile bitmap */
  347.       tile_data_end = (char *)( (int)tileset_ptr + sizeof(SF_MapTilesSetHdr) + (tile * sizeof(SF_MapTile)) + sizeof(SF_MapTile) ); /* start of tile */
  348.  
  349.       /* calculate address of start of sprite bitmap */
  350.       sprite_data_start = (char *)( (int)sph + sizeof(spriteheader)); /* start of sprite data */
  351.  
  352.       /* copy across raw bitmap */
  353.       for(int row = 0; row < SF_MAPTILE_HEIGHT; row++) {
  354.         /* notice that tile is reversed up/down during copying */
  355.         /* eg row 0-row 3,row 1-row 2,row 2-row 1, row 3-row 0 */
  356.         memcpy(
  357.           (char *)(sprite_data_start + (row * SF_MAPTILE_WIDTH)),
  358.           (char *)(tile_data_end - ((row+1) * SF_MAPTILE_WIDTH)),
  359.           SF_MAPTILE_WIDTH
  360.         );
  361.       } /* next row of tile */
  362.  
  363.     } /* loop back (next tile) */
  364.   }
  365.  
  366.   if(verify_spriteareas) {
  367.     /* Verify the sprite area that we have created */
  368.     if(E(_swix(OS_SpriteOp, _INR(0,1), SPRITEOP_VERIFY_AREA + SPRITEOP_USERAREA_SPRNAME, ret_sprarea_ptr))) {
  369.       flex_free((flex_ptr)ret_sprarea);
  370.       return false; /* fail */
  371.     }
  372.   }
  373.   hourglass_off();
  374.  
  375.   nobudge_deregister();
  376.   return true; /* success */
  377. }
  378.  
  379. /*
  380.    Routines read/write planet file FORMAT IV
  381.    e.g. mask and X,Y paint coordinates are obsolete
  382. */
  383.  
  384. bool sprites_to_planets(spriteareaheader **spritearea, SF_PlanetsSetHdr **ret_planetset, bool abandon_on_dud)
  385. {
  386.   /*
  387.   04.05.01 First version from sprites_to_tiles
  388.   10.05.01 Returns code indicating success
  389.            New param 'abandon_on_dud' controls behaviour with dud sprites
  390.   11.06.01 Queries dud sprites during prescan, can create empty planets files
  391.   02.11.01 Copes properly with funny sized header on input sprite area
  392.            Made parameters strongly typed
  393.   16.12.01 input and output blocks are both flexlib.
  394.   05.05.02 static pointers to flex blocks
  395.            more scopes to help register allocation
  396.   20.11.02 eliminated floats from hourglass percentage calculation
  397.   05.09.03 fixed memory leak of ret_planetset on error
  398.   */
  399.  
  400.   int max_planetnum;
  401.   spriteareaheader *spritearea_ptr;
  402.   SF_PlanetsSetHdr *ret_planetset_ptr;
  403.  
  404.   max_planetnum = get_max_planet_num(spritearea);
  405.   if(max_planetnum == -1) /* indicates too many sprites */
  406.     return false; /* failure */
  407.  
  408.   /* Allocate memory for planet set */
  409.   if(!flex_alloc((flex_ptr)ret_planetset, sizeof(SF_PlanetsSetHdr) + (sizeof(SF_PlanetBitmap)*2*(max_planetnum+1))))
  410.     MG_RETV("NoMem", false)
  411.  
  412.   nobudge_register(1024);
  413.   spritearea_ptr = *spritearea;
  414.   ret_planetset_ptr = *ret_planetset;
  415.  
  416.   /* Initialise planet set header */
  417.   memset(ret_planetset_ptr, 0, flex_size((flex_ptr)ret_planetset));
  418.   ret_planetset_ptr->lastplanet_num = max_planetnum;
  419.   for(int i = 0; i < 2; i++) {
  420.     ret_planetset_ptr->paintoffsets[i].xoffset=0;
  421.     ret_planetset_ptr->paintoffsets[i].yoffset=0;
  422.     ret_planetset_ptr->dataoffsets[i].dataoffset = sizeof(SF_PlanetsSetHdr) + (i*sizeof(SF_PlanetBitmap)*2);
  423.     ret_planetset_ptr->dataoffsets[i].maskoffset = ret_planetset_ptr->dataoffsets[i].dataoffset + sizeof(SF_PlanetBitmap);
  424.   }
  425.  
  426.   /* Scan sprite area */
  427.   hourglass_on();
  428.   {
  429.     spriteheader *input_sprite = (spriteheader *)((int)spritearea_ptr + spritearea_ptr->first);
  430.     for(int sprite = 0; sprite < spritearea_ptr->sprite_count; sprite++) {
  431.       hourglass_percentage((sprite * 100) / spritearea_ptr->sprite_count);
  432.  
  433.       /* Check source sprite header */
  434.       char spritename[13];
  435.       strncpy(spritename, input_sprite->name, sizeof(spritename)-1);
  436.       int planetnum = spritehdr_validpla(input_sprite, spritename);
  437.       if(planetnum >= 0) {
  438.         /* Copy across raw bitmap */
  439.         memcpy((void *)((int)ret_planetset_ptr + ret_planetset_ptr->dataoffsets[planetnum].dataoffset),
  440.                (void *)((int)input_sprite + input_sprite->image),
  441.                sizeof(SF_PlanetBitmap));
  442.  
  443.         /* And a pointless duplicate for backwards-compatibility */
  444.         memcpy((void *)((int)ret_planetset_ptr + ret_planetset_ptr->dataoffsets[planetnum].maskoffset),
  445.                (void *)((int)input_sprite + input_sprite->image),
  446.                sizeof(SF_PlanetBitmap));
  447.       }
  448.       else {
  449.         /* Invalid sprite header! */
  450.         nobudge_deregister();
  451.         hourglass_off();
  452.         
  453.         if(abandon_on_dud) {
  454.           /* Abandon rest of file with error */
  455.           err_report(255, msgs_lookup_sub1("BadSprite", spritename));
  456.           flex_free((flex_ptr)ret_planetset);
  457.           return false; /* failure */
  458.         }
  459.         if(!dialogue_confirm(msgs_lookup_sub1("BadSpriteCont", spritename))) {
  460.           flex_free((flex_ptr)ret_planetset);
  461.           return false; /* User wants to abandon rest of file */
  462.         }
  463.         else {
  464.           /* User wants to skip sprite and continue */
  465.           hourglass_on();
  466.           nobudge_register(1024);
  467.         }
  468.       }
  469.  
  470.       /* Calculate address of next sprite */
  471.       input_sprite = (spriteheader *)((int)input_sprite + input_sprite->size);
  472.  
  473.     } /* loop back (next sprite) */
  474.   }
  475.   hourglass_off();
  476.  
  477.   nobudge_deregister();
  478.   return true; /* success */
  479. }
  480.  
  481. /* ----------------------------------------------------------------------- */
  482.  
  483. bool planets_to_sprites(SF_PlanetsSetHdr **planetsset, spriteareaheader **ret_sprarea)
  484. {
  485.   /*
  486.      04.05.01 First version from BASIC converter and tiles_to_sprites
  487.      10.05.01 returns code indicating success
  488.      02.11.01 made parameters strongly typed and eliminated *outsize
  489.               returns error block
  490.      17.12.01 input and output blocks are both flexlib.
  491.      05.05.02 static pointers to flex blocks
  492.               more scopes to help register allocation
  493.      20.11.02 eliminated floats from hourglass percentage calculation
  494.    */
  495.   int numplanets;
  496.   spriteareaheader *ret_sprarea_ptr;
  497.   SF_PlanetsSetHdr *planetsset_ptr;
  498.  
  499.   /* read planets data details */
  500.   numplanets = (*planetsset)->lastplanet_num+1;
  501.   if (numplanets < 0 || numplanets > 2)
  502.     M_RETV("BadNumGFX", false)
  503.  
  504.   {
  505.     /* Allocate memory for sprite area */
  506.     int outsize = sizeof(spriteareaheader) + ((sizeof(spriteheader) + sizeof(SF_PlanetBitmap)) * numplanets);
  507.     if(!flex_alloc((flex_ptr)ret_sprarea, outsize))
  508.       MG_RETV("NoMem", false)
  509.  
  510.     nobudge_register(1024);
  511.     ret_sprarea_ptr = *ret_sprarea;
  512.     planetsset_ptr = *planetsset;
  513.  
  514.     /* initialise sprite area header */
  515.     ret_sprarea_ptr->size = outsize;
  516.     ret_sprarea_ptr->sprite_count = numplanets;
  517.     ret_sprarea_ptr->first = sizeof(spriteareaheader);
  518.     ret_sprarea_ptr->used = outsize;
  519.   }
  520.  
  521.   hourglass_on();
  522.   for(int planet = 0; planet < numplanets; planet++) {
  523.     spriteheader *sph;
  524.  
  525.     hourglass_percentage((planet * 100) / numplanets);
  526.  
  527.     /* initialise header of new sprite */
  528.     sph = (spriteheader *)((int)ret_sprarea_ptr + sizeof(spriteareaheader) + (planet * (sizeof(spriteheader) + sizeof(SF_PlanetBitmap)))); /* start of sprite */
  529.     sph->size = sizeof(spriteheader) + sizeof(SF_PlanetBitmap);
  530.     memset(sph->name, 0, sizeof(sph->name));
  531.     sprintf(sph->name, "planet_%d", planet);
  532.     sph->width = (SF_PLANET_WIDTH/4)-1;
  533.     sph->height = SF_PLANET_HEIGHT-1;
  534.     sph->left_bit = 0;
  535.     sph->right_bit = 31;
  536.     sph->image = sizeof(spriteheader);
  537.     sph->mask = sizeof(spriteheader);
  538.     if(output_new_format)
  539.       sph->type = OUTPUT_TYPE_NEW; /* New-style sprite type */
  540.     else
  541.       sph->type = OUTPUT_TYPE_MODE; /* old-style mode number */
  542.  
  543.     /* copy across raw bitmap */
  544.     memcpy((void *)((int)sph + sizeof(spriteheader)),
  545.            (void *)((int)planetsset_ptr + planetsset_ptr->dataoffsets[planet].dataoffset),
  546.             sizeof(SF_PlanetBitmap));
  547.  
  548.   } /* loop back (next planet) */
  549.  
  550.   if(verify_spriteareas) {
  551.     /* Verify the sprite area that we have created */
  552.     if(E(_swix(OS_SpriteOp, _INR(0,1), SPRITEOP_VERIFY_AREA + SPRITEOP_USERAREA_SPRNAME, ret_sprarea_ptr))) {
  553.       flex_free((flex_ptr)ret_sprarea);
  554.       return false; /* fail */
  555.     }
  556.   }
  557.   hourglass_off();
  558.  
  559.   nobudge_deregister();
  560.   return true; /* success */
  561. }
  562.  
  563. /* ----------------------------------------------------------------------- */
  564. /*                         Private functions                               */
  565.  
  566. static int check_spr_type(int type)
  567. {
  568.   /* Check that sprite type specifies 256 colours */
  569.   return (type == 10 /* Old sprite format, 8bpp mode numbers... */
  570.        || type == 13
  571.        || type == 15
  572.        || type == 21
  573.        || type == 24
  574.        || type == 28
  575.        || type == 32
  576.        || type == 36
  577.        || type == 40
  578.        || type>>27 == 4); /* New sprite format, 8bpp */
  579. }
  580.